#!/usr/bin/perl

use Carp;
use Term::ReadKey;
use Net::LDAP;
use Crypt::SmbHash;
use strict;

my $basedn = 'ou=People,dc=cs,dc=nctu,dc=edu,dc=tw';
my $masteruri = 'ldaps://ldapmaster.cs.nctu.edu.tw';
my $user = $ENV{'USER'};

&main();

sub InputPassword($)
{
	my $prompt = shift();

	my $pw;

	print($prompt);
	ReadMode(2);
	chomp($pw = ReadLine(0));
	ReadMode(0);
	print("\n");

	return $pw;
}

sub main()
{
  	my $mesg;

	croak("ERROR: cannot execute as user 'root'") if ($< == 0);

	my $oldpass = InputPassword("UNIX password for user ${user}: ");

	my $ldap = Net::LDAP->new( $masteruri );

	$mesg = $ldap->bind("uid=${user},${basedn}", password => $oldpass );	
	$mesg->code && die print("Wrong password for user ${user}!\n");

	my $type = '';
	my $unix = 0;
	my $win = 0;

	if ($0 =~ /unixpasswd/) {
		$type = ' UNIX';
		$unix = 1;
	} elsif ($0 =~ /winpasswd/) {
		$type = ' Windows';
		$win = 1;
	} else {
		$unix = $win = 1;
	}

	my $pass;
	my $pass2;

	while(1)
	{
	  $pass = InputPassword("New${type} password for user ${user}: ");
	  $pass2 = InputPassword("Retype new${type} password for user ${user}: ");
	  if($pass eq $pass2)
	  {
	      last;
	  }
	  print "Password mismatch.\n";
	}

	# MD5 password
	my $random = join('', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand(64), rand(64), rand(64), rand(64), rand(64), rand(64), rand(64), rand(64)]);
	my $modsalt = sprintf('$1$%s$', $random);
	my $password = crypt($pass, $modsalt);

	# Change time
	my $shadowlastchange = int(time() / 24 / 3600);
	my $pwdlastset = sprintf('%x', time());
	my $lmpassword;
	my $ntpassword;

	# LanManager and NT clear text passwords
	ntlmgen $pass, $lmpassword, $ntpassword;

	if($unix == 1)
      	{
		$mesg = $ldap->modify("uid=${user},${basedn}", replace =>
		  {	
		    "userpassword"	=>	"{crypt}${password}",
		    "shadowlastchange"	=>	$shadowlastchange
		  }
		);
		$mesg->code && die print ("Cannot change UNIX password!\n");
	}

	if ($win == 1)
	{
	  	$mesg = $ldap->modify("uid=${user},${basedn}", replace =>
		  {
		    "sambaLMPassword"	=>	$lmpassword,
		    "sambaNTPassword"	=>	$ntpassword
		  }
		);
		$mesg->code && die print ("Cannot change SAMBA password!\n");
	}

}
